package stone926.mods.more_enchantments.mixins;

import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.TntEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.world.World;
import net.minecraft.world.explosion.Explosion;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import stone926.mods.more_enchantments.damage.StoneEntityDamageSource;
import stone926.mods.more_enchantments.interfaces.ITNT;

import static stone926.mods.more_enchantments.nbt.CustomNbtKeys.TNT.*;

@Mixin(TntEntity.class)
public abstract class TntMixin extends Entity implements ITNT {

  private int power = 4;
  private Explosion.DestructionType destructionType = Explosion.DestructionType.BREAK;
  private boolean summonedByExplosionCreator = false;

  public TntMixin(EntityType<?> type, World world) {
    super(type, world);
  }

  @Shadow
  @Nullable
  public abstract LivingEntity getCausingEntity();

  @Override
  public int getPower() {
    return power;
  }

  @Override
  public void setPower(int power) {
    this.power = power;
  }

  @Override
  public Explosion.DestructionType getDestructionType() {
    return this.destructionType;
  }

  @Override
  public void setDestructionType(Explosion.DestructionType type) {
    this.destructionType = type;
  }

  @Inject(method = "readCustomDataFromNbt", at = @At("HEAD"))
  protected void readCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {
    if (nbt.contains(POWER)) setPower(nbt.getInt(POWER));
    if (nbt.contains(DESTRUCTION_TYPE))
      setDestructionType(getDestructionTypeFromString(nbt.getString(DESTRUCTION_TYPE)));
    if (nbt.contains(SUMMONED_BY_EXPLOSION_CREATOR))
      setSummonedByExplosionCreator(nbt.getBoolean(SUMMONED_BY_EXPLOSION_CREATOR));
  }

  @Inject(method = "writeCustomDataToNbt", at = @At("HEAD"))
  protected void writeCustomDataToNbt(NbtCompound nbt, CallbackInfo ci) {
    nbt.putInt(POWER, getPower());
    nbt.putString(DESTRUCTION_TYPE, getStringFromDestructionType(getDestructionType()));
    nbt.putBoolean(SUMMONED_BY_EXPLOSION_CREATOR, summonedByExplosionCreator());
  }

  private Explosion.DestructionType getDestructionTypeFromString(String str) {
    return switch (str) {
      case "destroy" -> Explosion.DestructionType.DESTROY;
      case "none" -> Explosion.DestructionType.NONE;
      default -> Explosion.DestructionType.BREAK;
    };
  }

  private String getStringFromDestructionType(Explosion.DestructionType type) {
    if (type == Explosion.DestructionType.DESTROY) return "destroy";
    else if (type == Explosion.DestructionType.NONE) return "none";
    else return "break";
  }

  @Redirect(method = "explode", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;createExplosion(Lnet/minecraft/entity/Entity;DDDFLnet/minecraft/world/explosion/Explosion$DestructionType;)Lnet/minecraft/world/explosion/Explosion;"))
  private Explosion explode(World world, Entity entity, double x, double y, double z, float power, Explosion.DestructionType type) {
    if (summonedByExplosionCreator()) {
      return world.createExplosion(entity, StoneEntityDamageSource.explosionCreator(getCausingEntity()), null, x, y, z, getPower(), false, getDestructionType());
    } else {
      return world.createExplosion(entity, x, y, z, power, type);
    }
  }

  @Override
  public boolean summonedByExplosionCreator() {
    return summonedByExplosionCreator;
  }

  @Override
  public void setSummonedByExplosionCreator(boolean summonedByExplosionCreator) {
    this.summonedByExplosionCreator = summonedByExplosionCreator;
  }

}
